/**
 * @ Author: luoqi
 * @ Create Time: 2025-02-13 21:23
 * @ Modified by: luoqi
 * @ Modified time: 2025-04-11 19:32
 * @ Description:
 */

#include <bsp.h>
#include "usb.h"
#include "../qshell/qterm.h"
#include "../modules/qmem.h"

static TX_THREAD task_usb;
static uint8_t task_stack_usb[1024];
static void task_usb_hdl(uint32_t args);
static QCliCmd cmd_usb;
static int cmd_usb_hdl(int argc, char **argv);

static TX_THREAD task_usb_send;
static uint8_t task_usb_send_stack[1024];
static void task_usb_send_hdl(uint32_t args);
static uint32_t interval_ms = 100;
static uint32_t send_us = 0;
uint8_t *test_data = NULL;
uint16_t test_data_sz = 100;

static QMem mem;
static uint8_t mempool[4096] = { 0 };

int usb_init(void)
{
    qmem_init(&mem, mempool, sizeof(mempool), 4, 16, 0x55);
    qterm_attach(&cmd_usb, "usb", cmd_usb_hdl, "usb commands");
    tx_thread_create(&task_usb, "usb", task_usb_hdl, 0, task_stack_usb, sizeof(task_stack_usb), 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
    test_data = qmem_alloc(&mem, test_data_sz);
    tx_thread_create(&task_usb_send, "usb_send_test", task_usb_send_hdl, 0, task_usb_send_stack, sizeof(task_usb_send_stack), 4, 4, TX_NO_TIME_SLICE, TX_DONT_START);
    return 0;
}


void task_usb_send_hdl(uint32_t args)
{
    UNUSED(args);
    for(uint16_t i = 0; i < test_data_sz; i++) {
        test_data[i] = i;
    }
    while(1) {
        uint64_t start = bsp_ktime();
        bsp_usb_send(test_data, test_data_sz);
        tx_thread_sleep(interval_ms);
        send_us = bsp_ktime() - start;
    }
}

void task_usb_hdl(uint32_t args)
{
    UNUSED(args);
    while(1) {
        uint8_t *data = qmem_alloc(&mem, 1024);
        int sz = bsp_usb_recv(data, 1024, TX_WAIT_FOREVER);
        if(sz > 0) {
            QSH(" [%d] bytes: ", sz);
            for(int i = 0; i < sz; i++) {
                QSH("%02X ", data[i]);
            }
            QSH("\r\n");
        } else {
            tx_thread_sleep(1);
        }
        qmem_free(&mem, data);
    }
}

static int args_test_hdl(int argc, char **argv)
{
    if(argc == 1) {
        QSH(" send us: %u\r\n", send_us);
        return 0;
    }
    if(ISARG(argv[1], "on") && argc == 2) {
        tx_thread_resume(&task_usb_send);
    } else if(ISARG(argv[1], "off") && argc == 2) {
        tx_thread_suspend(&task_usb_send);
    } else if(ISARG(argv[1], "frq") && argc == 3) {
        interval_ms = atoi(argv[2]);
    } else if(ISARG(argv[1], "sz") && argc == 3) {
        tx_thread_suspend(&task_usb_send);
        test_data_sz = atoi(argv[2]);
        qmem_free(&mem, test_data);
        test_data = qmem_alloc(&mem, test_data_sz);
        for(uint16_t i = 0; i < test_data_sz; i++) {
            test_data[i] = i;
        }
        tx_thread_resume(&task_usb_send);
    } else {
        return -1;
    }
    return 0;
}

static int args_send_hdl(int argc, char **argv)
{
    UNUSED(argc);
    uint64_t start = bsp_ktime();
    int ret = bsp_usb_send((uint8_t *)argv[1], bsp_strlen(argv[1]));
    QSH(" send %d bytes, using %lu us\r\n", ret, bsp_ktime() - start);
    return 0;
}

static QCliArgsEntry args_usb_table[] = {
    {"test", 2, 3, args_test_hdl, "<on/off> [frq <val>] [sz <val>]"},
    {"send", 2, 2, args_send_hdl, "<str>"},
};

static int cmd_usb_hdl(int argc, char **argv)
{
    if(argc == 1) {
        return 0;
    }
    if(ISARG(argv[1], "?") && (argc == 2)) {
        return qterm_help(args_usb_table, sizeof(args_usb_table));
    } 
    return qcli_args_handle(argc, argv, args_usb_table, sizeof(args_usb_table));
}
